package com.youlu.campus.admin.auth.service.impl;

import com.alibaba.fastjson.JSON;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
import com.youlu.campus.admin.auth.common.AuthConstants;
import com.youlu.campus.admin.auth.common.DeviceType;
import com.youlu.campus.admin.auth.dto.UserQueryRequest;
import com.youlu.campus.admin.auth.entity.SystemRole;
import com.youlu.campus.admin.auth.entity.SystemRoleUser;
import com.youlu.campus.admin.auth.entity.SystemUser;
import com.youlu.campus.admin.auth.entity.exception.AuthErrorCode;
import com.youlu.campus.admin.auth.service.AuthTokenService;
import com.youlu.campus.admin.auth.service.PasswordService;
import com.youlu.campus.admin.auth.service.RoleService;
import com.youlu.campus.admin.auth.service.UserService;
import com.youlu.campus.admin.auth.shiro.exception.AuthException;
import com.youlu.campus.admin.auth.shiro.token.AuthToken;

import com.youlu.campus.common.utils.SM2CryptUtils;
import com.youlu.campus.entity.WechatAuthBlackList;
import com.youlu.campus.service.wechat.WechatAuthBlackListService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.map.HashedMap;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.repository.support.PageableExecutionUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.regex.Pattern;

/**
 * Created by zhuhuaiqi
 */
@Service("userService")
public class UserServiceImpl implements UserService {
    Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);
    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    PasswordService passwordService;

    @Autowired
    RoleService roleService;

    @Autowired
    AuthTokenService authTokenService;
    @Autowired
    RedisTemplate redisTemplate;
    @Autowired
    private WechatAuthBlackListService wechatAuthBlackListService;


    private void create(SystemUser entity) {
        logger.info(":>>> 开始创建用户:{}", JSON.toJSONString(entity));
        entity.setCreatedTime(new Date());
        logger.debug("entity:{}", JSON.toJSONString(entity));
        mongoTemplate.insert(entity);
    }

    @Override
    public Boolean update(SystemUser entity) {
        logger.info(":>>> 开始修改用户:{}", JSON.toJSONString(entity));
        if (Objects.isNull(entity) || StringUtils.isBlank(entity.getId()) ||
                StringUtils.isBlank(entity.getTenantId())) {
            logger.error(":>>> 修改用户参数错误");
            throw new AuthException(AuthErrorCode.INVALID_ARGUMENT);
        }
        Query query = new Query();
        query.addCriteria(Criteria.where("id").is(entity.getId()).and("tenantId").is(entity.getTenantId()));
        Update update = new Update();
        if (StringUtils.isNotBlank(entity.getDomain())) {
            update.set("domain", entity.getDomain());
        }
        if (StringUtils.isNotBlank(entity.getLoginName())) {
            update.set("loginName", entity.getLoginName());
        }
        if (StringUtils.isNotBlank(entity.getMobile())) {
            update.set("mobile", entity.getMobile());
        }
        if (StringUtils.isNotBlank(entity.getRoleName())) {
            update.set("roleName", entity.getRoleName());
        }
        if (StringUtils.isNotBlank(entity.getRoleId())) {
            update.set("roleId", entity.getRoleId());
        }
        if (StringUtils.isNotBlank(entity.getNickName())) {
            update.set("nickName", entity.getNickName());
        }
        if (StringUtils.isNotBlank(entity.getRealName())) {
            update.set("realName", entity.getRealName());
        }
        if (Objects.nonNull(entity.getForbidden())) {
            update.set("forbidden", entity.getForbidden());
        }
        if (StringUtils.isNotBlank(entity.getEmail())) {
            update.set("email", entity.getEmail());
        }
        update.set("updatedTime", new Date());
        UpdateResult result = mongoTemplate.updateFirst(query, update, SystemUser.class);
        return result.getModifiedCount() > 0 ? true : false;
    }

    @Override
    public Page<SystemUser> query(UserQueryRequest userQueryRequest) {
        logger.info(":>>> 开始获取用户列表:{}", JSON.toJSONString(userQueryRequest));
        if (Objects.isNull(userQueryRequest)) {
            logger.error(":>>> 参数错误,请求参数为空");
            throw new AuthException(AuthErrorCode.INVALID_ARGUMENT);
        }
        Query query = new Query();
        query.addCriteria(Criteria.where("tenantId").is(userQueryRequest.getTenantId()));
        if (Objects.nonNull(userQueryRequest.getStatus()))
            query.addCriteria(Criteria.where("status").is(userQueryRequest.getStatus()));
        query.addCriteria(Criteria.where("deleted").ne(true));

        if (StringUtils.isNotBlank(userQueryRequest.getLoginName())) {
            Pattern pattern = Pattern.compile("^.*" + userQueryRequest.getLoginName() + ".*$", Pattern.CASE_INSENSITIVE);
            query.addCriteria(Criteria.where("loginName").regex(pattern));
        }
        if (StringUtils.isNotBlank(userQueryRequest.getRoleId())) {
            query.addCriteria(Criteria.where("roleId").is(userQueryRequest.getRoleId()));
        }
        if (StringUtils.isNotBlank(userQueryRequest.getMobile())) {
            query.addCriteria(Criteria.where("mobile").is(userQueryRequest.getMobile()));
        }
        if (StringUtils.isNotBlank(userQueryRequest.getRealName())) {
            Pattern pattern1 = Pattern.compile("^.*" + userQueryRequest.getRealName() + ".*$", Pattern.CASE_INSENSITIVE);
            query.addCriteria(Criteria.where("realName").regex(pattern1));
        }
        long count = mongoTemplate.count(query, SystemUser.class);
        PageRequest pageRequest = PageRequest.of(userQueryRequest.getPage() - 1, userQueryRequest.getPageSize());
//        query.with(new Sort(Sort.Direction.DESC, "createdTime"));
        Sort sort = Sort.by(Sort.Direction.DESC, "createdTime");
        query.with(sort);
        List<SystemUser> datas = mongoTemplate.find(query.with(pageRequest), SystemUser.class);
        return PageableExecutionUtils.getPage(datas, pageRequest, () -> count);
    }

    @Override
    public Boolean update(SystemUser entity, String[] roleIds) {
        logger.info(":>>> 开始更新用户:{},角色列表:{}", JSON.toJSONString(entity), JSON.toJSONString(roleIds));
        this.update(entity);
        if (roleIds != null) {
            this.updateRoles(entity.getTenantId(), entity.getId(), new ArrayList<>(Arrays.asList(roleIds)));
        }
        this.cleanUserDtoCache(entity.getId());
        this.clearUserCache(entity.getId());
        return true;
    }

    @Override
    public void delete(String id, String tenantId) {
        if (determineUserSuperAdministration(id)) {
            logger.warn("用户: {} 是超级管理员 无法被删除", id);
            return;
        }

        // 删除用户同时删除user_role表数据
        Query query = new Query();
        query.addCriteria(Criteria.where(tenantId).is(tenantId).and("userId").is(id));
        DeleteResult result = mongoTemplate.remove(query, SystemRoleUser.class);
        logger.debug(":>>> 除租户: {} 下的用户角色: {} 数量: {}", tenantId, id, result.getDeletedCount());
        DeleteResult result1 = mongoTemplate.remove(query, SystemUser.class);
        logger.debug(":>>> 除租户: {} 下的用户: {} 数量: {}", tenantId, id, result1.getDeletedCount());
        this.clearUserCache(id);
    }

    @Override
    public void delete(String id, String tenantId, String loginUserId) {
        //判断用户是否能被删除
        if (!isCanDeleteUser(id, loginUserId)) {
            logger.warn(":>>> 用户: {} 无法被删除", id);
            return;
        }
        // 删除用户同时删除user_role表数据
        Query query = new Query();
        query.addCriteria(Criteria.where(tenantId).is(tenantId).and("userId").is(id));
        DeleteResult result = mongoTemplate.remove(query, SystemRoleUser.class);
        logger.debug(":>>> 除租户: {} 下的用户角色: {} 数量: {}", tenantId, id, result.getDeletedCount());
        DeleteResult result1 = mongoTemplate.remove(query, SystemUser.class);
        logger.debug(":>>> 除租户: {} 下的用户: {} 数量: {}", tenantId, id, result1.getDeletedCount());
        this.clearUserCache(id);
    }

    private int addRoles(String tenantId, String userId, List<String> roleIds) {
        logger.info(":>>> 开始为租户:{},用户:{},添加橘色:{}", tenantId, userId, JSON.toJSONString(roleIds));
        if (StringUtils.isBlank(tenantId) || StringUtils.isBlank(userId) || CollectionUtils.isEmpty(roleIds)) {
            return 0;
        }
        int count = 0;
        for (String roleId : roleIds) {
            Query query = new Query();
            query.addCriteria(Criteria.where("tenantId").is(tenantId).and("userId").is(userId).and("roleId").is(roleId));
            boolean exist = mongoTemplate.exists(query, SystemRoleUser.class);
            if (!exist) {
                SystemRoleUser insert = new SystemRoleUser();
                insert.setCreatedTime(new Date());
                insert.setRoleId(roleId);
                insert.setUserId(userId);
                insert.setTenantId(tenantId);
                mongoTemplate.insert(insert);
                count++;
            }
        }
        return count;
    }

    @Override
    public boolean updatePwd(String userId, String tenantId, String password, String oldPassword) {
        logger.debug(":>>> AppUserServiceImpl.updatePwd params userId:{}, comId:{}, password:{}, oldPassword:{}",
                userId, tenantId, password, oldPassword);
        this.get(userId);
        SystemUser user = this.get(userId);
        if (Objects.isNull(user)) {
            logger.error(":>>> user is null,[$errorMsg] is:userId={}", userId);
            throw new AuthException(AuthErrorCode.USER_NOT_EXISTS);
        }
        if (!passwordService.validPassword(user, oldPassword)) {
            logger.error("old password is not right");
            throw new AuthException(AuthErrorCode.OLD_PASSWORD_NOT_MATCH);
        }
        return updatePassword(user, userId, tenantId, password);
    }

    @Override
    public boolean updatePwd(String userId, String tenantId, String password) {
        logger.debug(":>>> AppUserServiceImpl.updatePwd params comId:{}, userId:{}, passsword:{}", tenantId, userId,
                password);
        Query query = new Query();
        query.addCriteria(Criteria.where("tenantId").is(tenantId).and("id").is(userId));
        SystemUser user = mongoTemplate.findOne(query, SystemUser.class);
        if (user == null) {
            logger.error(":>>> user is null,[$errorMsg] is:userId={}", userId);
            throw new AuthException(AuthErrorCode.USER_NOT_EXISTS);
        }
        Update update = new Update();
        update.set("encPwd", password);
        update.set("passwordRetryNum", 0);
        update.set("updatedTime", new Date());
        UpdateResult result = mongoTemplate.updateFirst(query, update, SystemUser.class);
        return result.getModifiedCount() > 0 ? true : false;
//        return updatePassword(user, userId, tenantId, password);
    }

    @Override
    public boolean updateUserStatus(String userId, Integer status) {
        logger.info(":>>> AppUserServiceImpl.updateUserStatus userId:{}, status:{}", userId, status);
        long nowDate = System.currentTimeMillis();
        Query query = new Query();
        query.addCriteria(Criteria.where("id").is(userId));
        Update update = new Update();
        update.set("status", status);
        mongoTemplate.updateFirst(query, update, SystemUser.class);
        //TODO 添加用户登录日志，企业ID和用户名直接从缓存中获取
        try {
            //清除缓存
            this.clearUserCache(userId);

            //清除DTO缓存
            this.cleanUserDtoCache(userId);

            return true;
        } catch (Exception e) {
            logger.error(":>>> updateUserStatus error,[$errorMsg] is:\n{}", e);
            return false;
            //ignore
        }

    }

    private int updateRoles(String tenantId, String userId, List<String> roleIds) {

        List<String> comRoleIds = roleService.listRoleByUserIdAndComId(userId, tenantId);
        Query query = new Query();
        query.addCriteria(Criteria.where("tenantId").is(tenantId).and("userId").is(userId));
        DeleteResult result = mongoTemplate.remove(query, SystemRoleUser.class);
        logger.info(":>>> 删除租户:{},用户:{},角色数量:{}", tenantId, userId, result.getDeletedCount());
        Date date = new Date();
        for (String roleId : roleIds) {
            SystemRoleUser systemRoleUser = new SystemRoleUser();
            systemRoleUser.setTenantId(tenantId);
            systemRoleUser.setUserId(userId);
            systemRoleUser.setRoleId(roleId);
            systemRoleUser.setCreatedTime(date);
            mongoTemplate.insert(systemRoleUser);
        }
        // 清理用户信息缓存
        this.cleanUserDtoCache(userId);
        return roleIds.size();
    }

    /**
     * 根据userid获取角色列表
     *
     * @param userIdList
     * @return
     */
    @Override
    public Map<String, List<String>> getUserIdAndRoleMaps(List<String> userIdList) {
        Map<String, List<String>> data = new HashedMap();
        Query query = new Query();
        query.addCriteria(Criteria.where("userId").in(userIdList));
        List<SystemRoleUser> roleUsers = mongoTemplate.find(query, SystemRoleUser.class);
        if (CollectionUtils.isEmpty(roleUsers)) {
            logger.warn(":>>> 用户角色映射为空");
            return data;
        }
        for (SystemRoleUser systemRoleUser : roleUsers) {
            if (!data.get(systemRoleUser.getUserId()).contains(systemRoleUser.getRoleId())) {
                data.get(systemRoleUser.getUserId()).add(systemRoleUser.getRoleId());
            }
        }
        logger.info(":>>> 用户角色映射表:{}", JSON.toJSONString(data));
        return data;
    }

    @Override
    public List<SystemUser> listAll(String tenantId, Boolean isAvailable) {
        if (StringUtils.isBlank(tenantId) || Objects.isNull(isAvailable)) {
            logger.warn("参数 comId : {} 、 isAvailable: {} 不可为空", tenantId, isAvailable);
            return new ArrayList<>();
        }
        Query query = new Query();
        query.addCriteria(Criteria.where("tenantId").is(tenantId).and("available").is(isAvailable));
        List<SystemUser> users = mongoTemplate.find(query, SystemUser.class);
        logger.debug("查询 公司下所有User， 参数 tenantId : {} 、 isAvailable: {},大小:{}", tenantId, isAvailable, users.size());
        return users;
    }

    @Override
    public SystemUser get(String tenantId, String loginName, String domain) {
        logger.debug(":>>> 开始获取用户 loginName:{}, domain:{},tenantId:{}", loginName, domain, tenantId);
        if (StringUtils.isEmpty(loginName) || StringUtils.isEmpty(domain)) {
            logger.error(":>>> 参数错误:登陆名,domain为空");
            throw new AuthException(AuthErrorCode.INVALID_ARGUMENT);
        }
        Query query = new Query();
        query.addCriteria(Criteria.where("loginName").is(loginName).and("domain").is(domain));
        SystemUser systemUser = mongoTemplate.findOne(query, SystemUser.class);
        logger.debug("get user:{}", JSON.toJSONString(systemUser));
        if (Objects.isNull(systemUser)) {
            logger.error(":>>> 租户:{},用户:{},domain:{} 不存在", tenantId, loginName, domain);
            throw new AuthException(AuthErrorCode.USER_NOT_EXISTS);
        }
        return systemUser;
    }

    @Override
    public SystemUser getUserCache(String userId) {
        SystemUser user = null;
        user = this.get(userId);
        logger.debug("getUserCache from db user:{}", JSON.toJSONString(user));
        return user;
    }

    private void clearUserCache(String userId) {
        String key = getUserInfoRedisKey(userId);
        logger.debug("clearUserCache to redis key:{}", key);
    }


    @Override
    public void cleanUserDtoCache(String userID) {
        logger.debug("clean userDto cache by user id: {}", userID);
    }

    @Override
    public List<SystemUser> getUsersByStatusAndRole(String tenantId, Integer status, String identifier) {
        logger.debug(":>>> getUsersByStatusAndRole status is: {},role is: {}", status, identifier);
        if (StringUtils.isBlank(identifier)) {
            logger.error("identifier is null!");
            return null;
        }
        if (status == null) {
            logger.error("status is null!");
            return null;
        }
        Query query = new Query();
        query.addCriteria(Criteria.where("tenantId").is(tenantId).and("identifier").is(identifier));
        SystemRole systemRole = mongoTemplate.findOne(query, SystemRole.class);
        if (Objects.isNull(systemRole)) {
            logger.error(":>>> 租户:{},角色:{}", tenantId, identifier);
            return Collections.EMPTY_LIST;
        }
        Query query1 = new Query();
        query1.addCriteria(Criteria.where("tenantId").is(tenantId).and("roleId").is(systemRole.getId()));
        List<SystemRoleUser> roleUsers = mongoTemplate.find(query1, SystemRoleUser.class);
        if (CollectionUtils.isEmpty(roleUsers)) {
            return Collections.EMPTY_LIST;
        }
        List<String> userIds = new ArrayList<>();
        for (SystemRoleUser systemRoleUser : roleUsers) {
            if (!userIds.contains(systemRoleUser.getUserId())) {
                userIds.add(systemRoleUser.getUserId());
            }
        }
        Query query2 = new Query();
        query2.addCriteria(Criteria.where("id").in(userIds).and("status").is(status));
        return mongoTemplate.find(query2, SystemUser.class);
    }

    @Override
    public List<SystemUser> getUsersByComIdAndRole(String tenantId, String identifier) {
        logger.debug(":>>> getUsersByComIdAndRole ,role is: {}", identifier);
        if (StringUtils.isBlank(identifier)) {
            logger.error("identifier is null!");
            return null;
        }
        Query query = new Query();
        query.addCriteria(Criteria.where("tenantId").is(tenantId).and("identifier").is(identifier));
        SystemRole systemRole = mongoTemplate.findOne(query, SystemRole.class);
        if (Objects.isNull(systemRole)) {
            logger.error(":>>> 租户:{},角色:{}", tenantId, identifier);
            return Collections.EMPTY_LIST;
        }
        Query query1 = new Query();
        query1.addCriteria(Criteria.where("tenantId").is(tenantId).and("roleId").is(systemRole.getId()));
        List<SystemRoleUser> roleUsers = mongoTemplate.find(query1, SystemRoleUser.class);
        if (CollectionUtils.isEmpty(roleUsers)) {
            return Collections.EMPTY_LIST;
        }
        List<String> userIds = new ArrayList<>();
        for (SystemRoleUser systemRoleUser : roleUsers) {
            if (!userIds.contains(systemRoleUser.getUserId())) {
                userIds.add(systemRoleUser.getUserId());
            }
        }
        Query query2 = new Query();
        query2.addCriteria(Criteria.where("id").in(userIds));
        return mongoTemplate.find(query2, SystemUser.class);
    }

    @Override
    public void logoutCleanCache(String tenantId, String userId) {
        logger.info(":>>> 开始清理租户:{}, 用户:{} 缓存", tenantId, userId);
        Query query = new Query();
        query.addCriteria(Criteria.where("tenantId").is(tenantId).and("id").is(userId));
        Update update = new Update();
        update.set("status", 1);
        update.set("updatedTime", new Date());
        UpdateResult result = mongoTemplate.updateFirst(query, update, SystemUser.class);
        logger.info(":>>> 更新租户:{}, 用户:{} 状态为离线结果:{}", tenantId, userId, result.getModifiedCount() > 0 ? true : false);
        // 清除缓存
        authTokenService.clearAuthTokenCache(userId);
    }

    @Override
    public List<SystemUser> listAll(String tenantId, List<Integer> statuses) {
        logger.info(":<<< 开始获取租户:{},下状态为:{}", tenantId, JSON.toJSONString(statuses));
        Query query = new Query();
        query.addCriteria(Criteria.where("tenantId").is(tenantId).and("status").in(statuses));
        return mongoTemplate.find(query, SystemUser.class);
    }

    /**
     * 获取用户信息Redis Key前缀
     *
     * @param userId
     * @return
     */
    private String getUserInfoRedisKey(String userId) {
        return String.format(AuthConstants.REDIS_AUTH_USER_INFO, userId);
    }


    private boolean updatePassword(SystemUser user, String userId, String tenantId, String password) {
        Query query = new Query();
        query.addCriteria(Criteria.where("tenantId").is(tenantId).and("id").is(user));

        user.setEncPwd(password);
        passwordService.encryptPassword(user);
        Update update = new Update();
        update.set("encPwd", user.getEncPwd());
        update.set("updatedTime", new Date());
        UpdateResult result = mongoTemplate.updateFirst(query, update, SystemUser.class);
        this.cleanUserDtoCache(userId);
        this.clearUserCache(userId);
        return result.getModifiedCount() > 0 ? true : false;
    }

    private boolean determineUserSuperAdministration(String userId) {
        Query query = new Query();
        query.addCriteria(Criteria.where("id").is(userId));
        SystemUser user = mongoTemplate.findOne(query, SystemUser.class);
        if (user == null) {
            logger.error(":>>> 用户:{} 不存在", userId);
            throw new AuthException(AuthErrorCode.USER_NOT_EXISTS);
        }
        if (StringUtils.isEmpty(user.getRegMobile())) {
            logger.debug("用户:{} 的注册手机号是空 该用户不是超级管理员", userId);
            return false;
        } else {
            logger.debug("用户的注册手机号是:{} 该用户是超级管理员", user.getRegMobile());
            return true;
        }
    }

    @Override
    public SystemUser get(String id) {
        Query query = new Query();
        query.addCriteria(Criteria.where("id").is(id));
        return mongoTemplate.findOne(query, SystemUser.class);
    }


    @Override
    public List<String> getUserIdsByStatusAndRole(String tenantId, Integer status, String role) {
        List<SystemUser> userList = this.getUsersByStatusAndRole(tenantId, status, role);

        if (userList == null) {
            logger.error("userList is null!");
            return null;
        }
        if (userList.isEmpty()) {
            logger.debug("userList is empty!");
            return Collections.EMPTY_LIST;
        }

        List<String> userIdList = new ArrayList<String>();
        for (SystemUser user : userList) {
            if (user != null) {
                userIdList.add(user.getId());
            }
        }
        return userIdList;
    }

    @Override
    public List<String> getUserIdsByNotStatusAndRole(String tenantId, Integer status, String identifier) {
        logger.debug(":>>> tUserIdsByNotStatusAndRole status is: {},role is: {}", status, identifier);
        List<String> roleIdList = new ArrayList<>();
        if (StringUtils.isBlank(identifier)) {
            logger.error("identifier is null!");
            return roleIdList;
        }
        if (status == null) {
            logger.error("status is null!");
            return roleIdList;
        }

        SystemRole role = roleService.get(tenantId, identifier);
        logger.info(":>>> role is:{}", JSON.toJSON(role));
        if (role == null) {
            logger.error("role is not exist!");
            return roleIdList;
        }
        roleIdList.add(role.getId());
        return Collections.EMPTY_LIST;
    }


    @Override
    public SystemUser get(String tenantId, String regMobile, Boolean available) {
        logger.info(":>>> 开始获取用户 租户:{},注册手机号:{},是否可用:{}", tenantId, regMobile, available);
        if (StringUtils.isBlank(tenantId) || StringUtils.isBlank(regMobile) || Objects.isNull(available)) {
            return null;
        }
        Query query = new Query();
        query.addCriteria(Criteria.where("tenantId").is(tenantId).and("regMobile").is(regMobile).and("available").is(available));

        SystemUser systemUser = mongoTemplate.findOne(query, SystemUser.class);
        logger.info(":>>> 获取的用户信息为:{}", JSON.toJSONString(systemUser));
        return systemUser;
    }


    @Override
    public void create(SystemUser user, String[] roles, String tenantId) {
        Date current = new Date();
        user.setAvailable(true);
        user.setStatus(1);
        user.setTenantId(tenantId);
        user.setCreatedTime(current);
        user.setUpdatedTime(current);
        user.setBootstrapVersion(1);
        logger.debug("用户密码编码前: {}", JSON.toJSONString(user));
//        passwordService.encryptPassword(user);
        logger.debug("用户密码编码后: {}", JSON.toJSONString(user));
        this.create(user);
        this.addRoles(tenantId, user.getId(), new ArrayList(Arrays.asList(roles)));
    }

    @Override
    public boolean ifExists(String loginName, String domain) {
        logger.info(":>>> 开始判断用户是否存在:{},{}", loginName, domain);
        if (StringUtils.isBlank(loginName) || StringUtils.isBlank(domain)) {
            return false;
        }
        Query query = new Query();
        query.addCriteria(Criteria.where("loginName").is(loginName).and("domain").is(domain));
        return mongoTemplate.exists(query, SystemUser.class);
    }

    @Override
    public Long countByComId(String tenantId) {
        if (StringUtils.isBlank(tenantId)) {
            logger.error(":>>> 参数错误:{}", tenantId);
            return 0L;
        }
        Query query = new Query();
        query.addCriteria(Criteria.where("tenantId").is(tenantId).and("available").is(Boolean.TRUE));
        return mongoTemplate.count(query, SystemUser.class);
    }

    @Override
    public boolean isSupperAdmin(String domain, String loginName) {
        logger.debug(":>>> AppUserServiceImpl.isSupperAdmin domain:{}, loginName:{}", domain, loginName);
        Query query = new Query();
        query.addCriteria(Criteria.where("domain").is(domain).and("loginName").is(loginName));

        SystemUser user = mongoTemplate.findOne(query, SystemUser.class);
        if (Objects.isNull(user)) {
            logger.error(":>>> 域:{},登录名:{},用户不存在", domain, loginName);
            return false;
        }
        String regMobile = user.getRegMobile();
        logger.debug(":>>> AppUserServiceImpl.isSupperAdmin regMobile:{}", regMobile);
        if (StringUtils.isNotEmpty(regMobile)) {
            return true;
        }
        return false;
    }


    @Override
    public boolean updateUserStatus(String userId, DeviceType deviceType, Integer status) {
        logger.debug(":>>> serServiceImpl.updateUserStatus userId:{}, deviceType:{}, status:{}",
                userId, deviceType, status);
        try {
            String key = getAuthTokenRedisKey(userId);
            String json = (String) redisTemplate.opsForValue().get(key);
            if (StringUtils.isEmpty(json)) {
                return false;
            }
            logger.debug(":>>> AppUserServiceImpl.updateUserStatus authToken:{}", json);
            AuthToken authToken = JSON.parseObject(json, AuthToken.class);
            if (!deviceType.equals(authToken)) {
                return false;
            }
            this.updateUserStatus(userId, status);
        } catch (Exception e) {
            logger.error(":>>> 更新用户状态错误:{}", e);
            return false;

        }
        return true;
    }

    @Override
    @Async
    public void updateFirstLogin(SystemUser user) {
        logger.info(":>>> 开始更新首次登陆标记:{}", user.getLoginName());
        Query query = new Query();
        query.addCriteria(Criteria.where("id").is(user.getId()));
        Update update = new Update();
        update.set("firstLogin", Boolean.FALSE);
        mongoTemplate.updateFirst(query, update, SystemUser.class);
    }
    @Override
    public boolean reBatchUpdatePwd(String systemAppId) {
        Date date=new Date();
        List<SystemUser> users = mongoTemplate.findAll(SystemUser.class);
        for (SystemUser user : users) {
            Query query = new Query();
            query.addCriteria(Criteria.where("id").is(user.getId()));
            Update update = new Update();
            update.set("encPwd", user.getPwdBack());
            update.set("updateTime", date);
            mongoTemplate.updateFirst(query, update, SystemUser.class);
        }
        return true;
    }

    @Override
    public boolean batchModifyPassword(String systemAppId) {
        WechatAuthBlackList we = wechatAuthBlackListService.findBySysAppId(systemAppId);
        if (Objects.isNull(we)) {
            logger.error(":>>> 平台配置不存在systemAppId:{}", systemAppId);
            return false;
        }
        Date date=new Date();
        List<SystemUser> users = mongoTemplate.findAll(SystemUser.class);
        for (SystemUser user : users) {
            String dP = SM2CryptUtils.encrypt(user.getEncPwd(), we.getPublicKey());
            Query query = new Query();
            query.addCriteria(Criteria.where("id").is(user.getId()));
            Update update = new Update();
            update.set("encPwd", dP);
            update.set("pwdBack", user.getEncPwd());
            update.set("updateTime", date);
            mongoTemplate.updateFirst(query, update, SystemUser.class);
        }
        return true;
    }


    /**
     * 判断用户是否能被删除
     *
     * @param userId
     * @return true 能被删除，否则不能被删除
     */
    private boolean isCanDeleteUser(String userId, String loginUserId) {
        logger.info(":>>> AppUserServiceImpl.isCanDeleteUser userId:{}, loginUserId:{}", userId, loginUserId);
        Query query = new Query();
        query.addCriteria(Criteria.where("id").is(userId));
        SystemUser user = mongoTemplate.findOne(query, SystemUser.class);
        if (Objects.isNull(user)) {
            logger.warn("userId:{} get user is null.", userId);
            return false;
        }


        if (user.getId().equals(loginUserId)) {
            throw new AuthException(AuthErrorCode.USER_NOT_DELETE_SELF);
        }

        if (StringUtils.isNotEmpty(user.getRegMobile())) {
            logger.warn("用户的注册手机号是:{} 该用户是超级管理员", user.getRegMobile());
            //超级管理员不能补删除
            throw new AuthException(AuthErrorCode.USER_NOT_DELETE_SELF);
        }
        return true;
    }

    private String getAuthTokenRedisKey(String userId) {
        return String.format(AuthConstants.REDIS_AUTH_USER_TOKEN, userId);
    }

}
